package com.yjc.manager.scanner;

import com.yjc.manager.entity.JarInfo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类扫描
 */
public class ClassScanner {
    /**
     * class文件的后缀
     */
    private static final String CLASS_FILE_SUFFIX = ".class";

    /**
     * 扫描目录下jar包中的class
     * @param path 路径文件夹名称
     * @return
     * @throws IOException
     */
    public static List<JarInfo> findJarInfoListByPath(String path) throws Exception {
        File file = new File(path);
        List<JarInfo> jarInfoList = new ArrayList();
        findJarFile(file,jarInfoList);
        return jarInfoList;
    }

    /**
     * 扫描指定jar包中的class
     * @param path
     * @param jarName
     * @return
     * @throws IOException
     */
    public static JarInfo findJarInfoListByFile(String jarPath, String jarName) throws Exception {
        File file = new File(jarPath+File.separator+jarName+".jar");
        return findAndAddClassesByJar(file,jarName);
    }

    private static void findJarFile(File file,List<JarInfo> jarInfoList) throws IOException {
        for (File listFile : file.listFiles()) {
            if (listFile.isDirectory()){
                findJarFile(listFile, jarInfoList);
            }else if(isJarFile(listFile)){
                JarInfo jarInfo = findAndAddClassesByJar(listFile, listFile.getName());
                jarInfoList.add(jarInfo);
            }
        }
    }

    private static JarInfo findAndAddClassesByJar(File file, String fileName) throws IOException {
        URL url = new URL("jar:file:" + file.getAbsolutePath() + "!/");
        List<String> classNameList = new ArrayList<>();
        JarInfo jarInfo = new JarInfo(fileName, new URL[]{url}, classNameList);
        JarFile jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()){
            JarEntry jarEntry = entries.nextElement();
            if (jarEntry.getName().endsWith(CLASS_FILE_SUFFIX)){
                //全限定类名
                String className = jarEntry.getName().replace('/', '.').substring(0, jarEntry.getName().length() - 6);
                classNameList.add(className);
            }
        }
        return jarInfo;
    }

    private static boolean isJarFile(File file) {
        if (file == null || !file.exists()) {
            return false;
        }

        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] bytes = new byte[2];
            fis.read(bytes, 0, 2);

            return bytes[0] == 'P' && bytes[1] == 'K';
        } catch (IOException e) {
            // exception ignore
            return false;
        }
    }
}
